#include <stdio.h>
#include <stdint.h>
#include <stdlib.h> // exit
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

#include "syscore.h"
#include "apis.h"
#include "common.h" 
#include "modules.h"

#define fwm_shell "fwm.sh"

typedef enum tag_fw_ret {
    fw_ret_ok = 0,
    fw_ret_nok,
    fw_not_found,
    fw_off,
    fw_not_supported,
    fw_err_param,
    fw_err_md5sum,
    fw_err_download,
    fw_err_upg_in_progress,
    fw_err_decompress,
    fw_err_write_kernel,
    fw_err_write_rootfs,
    fw_err_write_x86app,
    fw_ret_upgrade_fdd,
    fw_ret_upgrade_tdd,
    fw_ret_upgrade_allBaseBand,
    fw_ret_upgrade_all,
    fw_ret_upgrade_x86AndFdd,
    fw_ret_upgrade_x86AndTdd,
    fw_ret_upgrade_gsm
} fw_ret_t;

MODREG mod_fwmgr_info = {MODULE_FWMGR, false, false, 100, NULL};
bool stop_fwmgr_thread = false;
char fw_url[1024] = {0};
char fw_md5sum[64] = {0};
char filename[256] = {0};
char fw_pkg[64] = {0};

int32_t rx_queue_id = 0;
int32_t tx_queue_id = 0;

bool send_qmsg(char *msg, U16 length)
{
    int ret_value = msgsnd(tx_queue_id, msg, length, 0);  
    if( ret_value < 0 ) 
    {  
        printf("msgsnd() msg failed mtype=%ld, length=%d, errno=%d[%s]\n", 
                *(long*)msg, length, errno, strerror(errno));  
        return false;  
    }
    return true;
}

void reportFwmgrUpgrade(uint32_t upgradeState)
{
    
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_FWMGR;
    msg_header->dstID = MODULE_SYSMONITOR;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType =  CMD_EVENT;
    cmd->cmdCode = CMD_CODE_FWM_DOWNING;
    cmd->cmdIndex = 0;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);
    uint8_t *ptr = (uint8_t *)msg_payload;
    ptr += sizeof(CMDHEADER);

    *(uint32_t*)ptr = PARA_TYPE_FWM_DOWNLOAD_STATE;
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = sizeof(uint32_t);
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = upgradeState;
    cmd->cmdLength += sizeof(uint32_t) * 4;
    

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg((char *)msg_header, msg_header->msgLength) )
    {
        printf("%s, can't report msg, mtype=%d length=%d \n", __func__, 
                msg_header->msgType, msg_header->msgLength);
    }
  
}

void reportFwmgrHeartBeat()
{
    U32 rc  = PARA_VALUE_SYSMONITOR_MODULE_OK;
        
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_FWMGR;
    msg_header->dstID = MODULE_SYSMONITOR;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType =  CMD_EVENT;
    cmd->cmdCode = CMD_CODE_SYSMONITOR_HEARTBEAT;
    cmd->cmdIndex = 0;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);
    uint8_t *ptr = (uint8_t *)msg_payload;
    ptr += sizeof(CMDHEADER);

    *(uint32_t*)ptr = PARA_TYPE_SYSMONITOR_MODULE_STATE;
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = sizeof(uint32_t);
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = rc;
    cmd->cmdLength += sizeof(uint32_t) * 4;
    

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg((char *)msg_header, msg_header->msgLength) )
    {
        printf("%s, can't report msg, mtype=%d length=%d \n", __func__, 
                msg_header->msgType, msg_header->msgLength);
    }
  
}

void reportFwmgrUpgardeBbu(uint16_t dst_id, uint16_t cmd_code, uint16_t cmd_idx, uint32_t result, uint32_t type)
{
    int bbu_type = PARA_VALUE_UPGRADE_X86;;
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_FWMGR;
    msg_header->dstID = dst_id;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_SET_RESPONSE;
    cmd->cmdCode = cmd_code;
    cmd->cmdIndex = cmd_idx;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);
    uint8_t *ptr = (uint8_t *)msg_payload;
    ptr += sizeof(CMDHEADER);


    *(uint32_t*)ptr = PARA_TYPE_RESULT;
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = sizeof(uint32_t);
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = result;
    ptr += sizeof(uint32_t) + sizeof(uint32_t);
    cmd->cmdLength += sizeof(uint32_t) * 4;
  
    if ((type == fw_ret_upgrade_fdd))
        bbu_type = PARA_VALUE_UPGRADE_FDD;
    else if (type == fw_ret_upgrade_tdd)
        bbu_type = PARA_VALUE_UPGRADE_TDD;
    else if (type == fw_ret_upgrade_allBaseBand)
        bbu_type = PARA_VALUE_UPGRADE_ALL_BASEBAND;
    else if ( type == fw_ret_upgrade_x86AndFdd)
        bbu_type = PARA_VALUE_UPGRADE_X86ANDFDD;
    else if ( type == fw_ret_upgrade_x86AndTdd)
        bbu_type = PARA_VALUE_UPGRADE_X86ANDTDD;
    else if (type == fw_ret_upgrade_all)
        bbu_type = PARA_VALUE_UPGRADE_ALL;
    else if (type == fw_ret_upgrade_gsm)
        bbu_type = PARA_VALUE_UPGRADE_GSM;
    *(uint32_t*)ptr = PARA_TYPE_UPGRADE_TYPE;
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = sizeof(uint32_t);
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = bbu_type;
    cmd->cmdLength += sizeof(uint32_t) * 4;

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg(msg_buf, msg_header->msgLength) )
    {
        printf("%s, can't report msg, mtype=%d length=%d \n", __func__, 
                msg_header->msgType, msg_header->msgLength);
    }
}


void reportFwmgrCmdResult(uint16_t dst_id, uint16_t cmd_code, uint16_t cmd_idx, uint32_t result, uint32_t err_code)
{
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_FWMGR;
    msg_header->dstID = dst_id;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_SET_RESPONSE;
    cmd->cmdCode = cmd_code;
    cmd->cmdIndex = cmd_idx;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);
    uint8_t *ptr = (uint8_t *)msg_payload;
    ptr += sizeof(CMDHEADER);

    if( PARA_VALUE_RESULT_FAILED == result )
    {
        *(uint32_t*)ptr = PARA_TYPE_RESULT;
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = sizeof(uint32_t);
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = PARA_VALUE_RESULT_FAILED;
        ptr += sizeof(uint32_t) + sizeof(uint32_t);
        cmd->cmdLength += sizeof(uint32_t) * 4;

        *(uint32_t*)ptr = PARA_TYPE_ERROR_CODE;
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = sizeof(uint32_t);
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = PARA_VALUE_ERROR_FW_OK + err_code;
        cmd->cmdLength += sizeof(uint32_t) * 4;
    }
    else
    {
        *(uint32_t*)ptr = PARA_TYPE_RESULT;
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = sizeof(uint32_t);
        ptr += sizeof(uint32_t);
        *(uint32_t*)ptr = result;
        cmd->cmdLength += sizeof(uint32_t) * 4;
    }

    msg_header->msgLength += cmd->cmdLength;

    if( ! send_qmsg(msg_buf, msg_header->msgLength) )
    {
        printf("%s, can't report msg, mtype=%d length=%d \n", __func__, 
                msg_header->msgType, msg_header->msgLength);
    }
}

void request_reboot()
{
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_FWMGR;
    msg_header->dstID = MODULE_SYSTEM;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType = CMD_SET;
    cmd->cmdCode = CMD_CODE_SYS_REBOOT;
    cmd->cmdIndex = 0;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);

    if( ! send_qmsg(msg_buf, msg_header->msgLength) )
    {
        printf("%s, can't report msg, mtype=%d length=%d \n", __func__, 
                msg_header->msgType, msg_header->msgLength);

		sleep(5);
		system("reboot -f");
    }
}

int32_t fw_download(char *url, char *md5sum, char *filename)
{
    int32_t ret = fw_ret_ok;
    char cmd[1024] = {0};
    char result[256] = {0};

    sprintf(cmd, "%s -d %s -m %s -n %s\n", fwm_shell, url, md5sum, filename);

    if( ! execShellCommand(cmd, result, 256) )
    {
        printf("%s, exec shell command failed, result:\n%s\n", __func__, result);

        MOD_log(MODULE_FWMGR, LOG_ERR, "%s, execShellCommand failed, result:\n%s\n", __func__, result);		
        return fw_ret_nok;
    }

    printf("%s, exec shell command result:\n%s\n", __func__, result);
    MOD_log(MODULE_FWMGR, LOG_INFO, "%s, execShellCommand succeed result:\n%s\n", __func__, result);
    if (strcmp(result, "upgradeTDD") == 0)
    {
        ret = fw_ret_upgrade_tdd;
    }
    else if (strcmp(result, "upgradeFDD") == 0)
    {
        ret = fw_ret_upgrade_fdd;
    }
    else if (strcmp(result, "upgradeAllBaseband") == 0)
    {
        ret = fw_ret_upgrade_allBaseBand;
    }
    else if (strcmp(result, "upgradeAll") == 0)
    {
        ret = fw_ret_upgrade_all;
    }
    else if (strcmp(result, "upgradex86AndFdd") == 0)
    {
        ret = fw_ret_upgrade_x86AndFdd;
    }
    else if (strcmp(result, "upgradex86AndTdd") == 0)
    {
        ret = fw_ret_upgrade_x86AndTdd;
    }
    else if (strcmp(result, "upgradeGSM") == 0)
    {
        ret = fw_ret_upgrade_gsm;
    }
    else if( strcmp(result, "done") == 0 )
    {
        ret = fw_ret_ok;
    }
    else if( strcmp(result, "download_failed") == 0 )
    {
        ret = PARA_VALUE_ERROR_FW_ERR_DOWNLOAD;
    }
    else if( strcmp(result, "md5sum_mismatch") == 0 )
    {
        ret = PARA_VALUE_ERROR_FW_ERR_MD5SUM;
    }
    else if( strcmp(result, "noclean") == 0 )
    {
        ret = PARA_VALUE_ERROR_FW_ERR_UPG_IN_PROGRESS;
    }
    else if( strcmp(result, "pkg_decompress_failed") == 0 )
    {
        return PARA_VALUE_ERROR_FW_ERR_DECOMPRESS;
    }
    else if( strcmp(result, "write_kernel_failed") == 0 )
    {
        return PARA_VALUE_ERROR_FW_ERR_WRITE_KERNEL;
    }
    else if( strcmp(result, "write_rootfs_failed") == 0 )
    {
        return PARA_VALUE_ERROR_FW_ERR_WRITE_ROOTFS;
    }
    else if( strcmp(result, "write_x86app_failed") == 0 )
    {
        return PARA_VALUE_ERROR_FW_ERR_WRITE_X86APP;
    }
    else
    {
        ret = fw_ret_nok;
    }

    return ret;
}

fw_ret_t fw_install(char *pkg_name)
{
    fw_ret_t ret = fw_ret_ok;
    char cmd[1024] = {0};
    char result[256] = {0};

    sprintf(cmd, "%s -i %s \n", fwm_shell, pkg_name);

    if( ! execShellCommand(cmd, result, 256) )
    {
        printf("%s, exec shell command failed, result:\n%s\n", __func__, result);
        return fw_ret_nok;
    }

    printf("%s, exec shell command result:\n%s\n", __func__, result);
    if( strcmp(result, "pkg_decompress_failed") == 0 )
    {
        return fw_err_decompress;
    }
    else if( strcmp(result, "write_kernel_failed") == 0 )
    {
        return fw_err_write_kernel;
    }
    else if( strcmp(result, "write_rootfs_failed") == 0 )
    {
        return fw_err_write_rootfs;
    }
    else if( strcmp(result, "write_x86app_failed") == 0 )
    {
        return fw_err_write_x86app;
    }
    else if (strcmp(result, "done") == 0)
    {
        ret = fw_ret_ok;
    }
    else 
    {
        ret = fw_ret_nok;
    }

    return fw_ret_ok;
}

fw_ret_t fw_installIpk()
{
    fw_ret_t ret = fw_ret_ok;
    char cmd[1024] = {0};
    char result[256] = {0};

    sprintf(cmd, "%s -I  \n", fwm_shell);

    if( ! execShellCommand(cmd, result, 256) )
    {
        printf("%s, exec shell command failed, result:\n%s\n", __func__, result);
        return fw_ret_nok;
    }

    printf("%s, exec shell command result:\n%s\n", __func__, result);
    if( strcmp(result, "write_x86app_failed") == 0 )
    {
        return fw_err_write_x86app;
    }
    else if (strcmp(result, "done") == 0)
    {
        ret = fw_ret_ok;
    }
    else 
    {
        ret = fw_ret_nok;
    }

    return fw_ret_ok;
}

fw_ret_t factory_reset()
{
    char cmd[1024] = {0};
    char result[256] = {0};

    sprintf(cmd, "%s -f \n", fwm_shell);

    if( ! execShellCommand(cmd, result, 256) )
    {
        printf("%s, exec shell command failed, result:\n%s\n", __func__, result);
        return fw_ret_nok;
    }

    return fw_ret_ok;
}

fw_ret_t reboot_x86board()
{
    char cmd[1024] = {0};
    char result[256] = {0};

    sprintf(cmd, "%s -r \n", fwm_shell);

    if( ! execShellCommand(cmd, result, 256) )
    {
        printf("%s, exec shell command failed, result:\n%s\n", __func__, result);
        return fw_ret_nok;
    }

    return fw_ret_ok;
}

void fwmgr_tlvmsg_hdlr(PMSGHEADER header)
{
    int32_t ret = fw_ret_ok;
    uint32_t len = header->msgLength, cmd_len = 0;
    uint8_t *ptr = ((uint8_t*)header) + sizeof(MSGHEADER);
    uint16_t srcId = header->srcID;

    if( MODULE_FWMGR != header->dstID )
    {
        printf("%s, received a wrong tlv dst id = %d \n", __func__, header->dstID);
        return;
    }

    if( MSG_TYPE_COMMAND == header->msgType )
    {
    
        PCMDHEADER cmd = (PCMDHEADER)ptr;
        ptr += sizeof(CMDHEADER);
        len -= sizeof(CMDHEADER);

        cmd_len = cmd->cmdLength;

        if( CMD_SET == cmd->cmdType )
        {
            switch( cmd->cmdCode ) {
				
            case CMD_CODE_SYS_UPGRADE:
                {
                    uint32_t tlvRecvFlag = 0;

                    while( (cmd_len >= sizeof(PARAM)) && (fw_ret_ok == ret) )
                    {
                        PARAM *tlv = (PARAM *)ptr;
                        int32_t tlvLength = roundup8(sizeof(PARAM) + tlv->paraLength);

                        switch( tlv->paraType ) {
							
                            case PARA_TYPE_SYS_UPGRADE_URL:
								
                                memcpy(fw_url, tlv->paraValue, tlv->paraLength);
                                printf("usrl=====%s len == %d", tlv->paraValue,tlv->paraLength );
                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                tlvRecvFlag |= 1;
                                break;
								
                            case PARA_TYPE_SYS_UPGRADE_MD5SUM:
                                if( tlv->paraLength == 32 )
                                {
                                    memcpy(fw_md5sum, tlv->paraValue, tlv->paraLength);
                                printf("usrl=====%s len == %d \n", tlv->paraValue,tlv->paraLength );
                                }
                                else
                                {
                                    printf("%s, recv wrong tlv, length=%u\n", __func__, tlv->paraLength);
                                    ret = fw_err_param;
                                    break;
                                }

                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                tlvRecvFlag |= 2;
                                break;

                            case PARA_TYPE_FWM_UPGRADE_FIEL_NAME:
                                memcpy(filename, tlv->paraValue, tlv->paraLength);
                                printf("filename=====%s len == %d", filename, tlv->paraLength );
                                ptr += tlvLength;
                                cmd_len -= tlvLength;
                                tlvRecvFlag |= 4;
                                break; 
                                
                            default:
                                printf("%s, tlv type %d not supported \n", __func__, tlv->paraType);
                                ret = fw_not_supported;
                                break;
                        }
                    }

                    if( fw_ret_ok == ret )
                    {
                        if( tlvRecvFlag == 0x7 )
                        {
                            printf("firmware upgrade request received, url is %s, md5sum is %s\n", fw_url, fw_md5sum);

                            MOD_log(MODULE_FWMGR, LOG_ERR, "firmware upgrade request received, url is %s, md5sum is %s\n", fw_url, fw_md5sum);

                            reportFwmgrCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex, PARA_VALUE_RESULT_DOING, PARA_VALUE_ERROR_NO_ERROR);
                            reportFwmgrUpgrade(PARA_VALUE_DOWNLOAD_START);
                            ret = fw_download(fw_url, fw_md5sum, filename);
                            reportFwmgrUpgrade(PARA_VALUE_DOWNLOAD_END);
                            if( fw_ret_ok == ret )
                            {
                                
                                printf("%s, firmware download done \n", __func__);
                                MOD_log(MODULE_FWMGR, LOG_ERR, "firmware download done \n", __func__);

                                reportFwmgrCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex,
                                    PARA_VALUE_RESULT_SUCCESS, PARA_VALUE_ERROR_NO_ERROR);

                                MOD_log(MODULE_FWMGR, LOG_ERR, "System upgrade requests to reset system \n");
                                createRestartCauseFileByCode(SYSTEM_SOFTWARE_UPGRADE);
                                request_reboot();
                                 
                                return;
                            }
                            else if ((ret == fw_ret_upgrade_fdd) || (ret == fw_ret_upgrade_tdd) || (ret == fw_ret_upgrade_all) ||
                                     (ret == fw_ret_upgrade_x86AndFdd) || (ret == fw_ret_upgrade_x86AndTdd) || (ret == fw_ret_upgrade_allBaseBand)
                                     || ret == fw_ret_upgrade_gsm)
                            {
                                printf("%s, firmware download done \n", __func__);
                                MOD_log(MODULE_FWMGR, LOG_ERR, "firmware FDD OR TDD download done \n", __func__);
                               reportFwmgrUpgardeBbu(srcId, cmd->cmdCode, cmd->cmdIndex,
                                    PARA_VALUE_RESULT_SUCCESS, ret);
                               return;
                            }
                        }
                        else
                        {
                            printf("%s, tlv missing detected \n", __func__);
                            ret = fw_err_param;
                        }
                    }
                    else
                    {
                        ret = fw_err_param;
                    }
                }
                break;
			
            case CMD_CODE_FWM_INSTALL:
            {
                UNPACK_RESULT uprc;
                PPARAM pParam =(PPARAM)(cmd+1);
                uint32_t len = cmd->cmdLength;
                uint32_t paraType;
                uint32_t paraLength = 0;
                uint8_t* paraValue = NULL;
                uint32_t tlvRecvFlag = 0;

                while((uprc=CM_paraUnpackPara(&pParam, &len, &paraType, &paraLength,&paraValue)) == UNPACK_OK)
                {
                    if(paraType == PARA_TYPE_SYS_UPGRADE_PKG)
                    {  
                         memcpy(fw_pkg, paraValue, paraLength); 
                         tlvRecvFlag |= 1;
                    }
                    if(fw_ret_ok == ret)
                    {
                        if(tlvRecvFlag == 0x1)
                        {
                            printf("x86proj upgrade request, pkg name is:%s \n", fw_pkg);
                            MOD_log(MODULE_FWMGR, LOG_INFO, "x86proj upgrade request, pkg name is: ", fw_pkg);
 //                           reportFwmgrCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex, PARA_VALUE_RESULT_DOING,PARA_VALUE_ERROR_NO_ERROR);
                        
                            ret = fw_install(fw_pkg); 
                    
                            if(fw_ret_ok == ret)
                            {
                                printf("%s, x86_upgrate done \n", __func__);
                                reportFwmgrCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex,
                                                        PARA_VALUE_RESULT_SUCCESS, PARA_VALUE_ERROR_NO_ERROR);
                                MOD_log(MODULE_FWMGR, LOG_INFO, "System upgrade request to reset system \n");
                                request_reboot();
                                return;
                            }
                        }
                        else
                        {
                            printf("%s, tlv misssing detected \n", __func__);
                            ret = fw_err_param;
                        }
                    }
                }
            }
            break;
              
            case CMD_CODE_FWM_UPGRADE_X86:
               {
                   ret = fw_installIpk(); 
                    
                   if(fw_ret_ok == ret)
                   {
                        createRestartCauseFileByCode(SYSTEM_SOFTWARE_UPGRADE);
                        printf("%s, x86_upgrate done \n", __func__);
                        reportFwmgrCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex,
                                                        PARA_VALUE_RESULT_SUCCESS, PARA_VALUE_ERROR_NO_ERROR);
                        MOD_log(MODULE_FWMGR, LOG_INFO, "System upgrade request to reset system \n");
                        request_reboot();
                        return;
                   }
               }
               break;

            case CMD_CODE_FWM_FACTORY_RESET:
                printf("Factory reset request received \n");
                MOD_log(MODULE_FWMGR, LOG_ERR, "Factory reset request received \n");

//                reportFwmgrCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex, PARA_VALUE_RESULT_DOING, PARA_VALUE_ERROR_NO_ERROR);

                ret = factory_reset();
                if( fw_ret_ok == ret )
                {
                    reportFwmgrCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex,
                        PARA_VALUE_RESULT_SUCCESS, PARA_VALUE_ERROR_NO_ERROR);

                    MOD_log(MODULE_FWMGR, LOG_ERR, "Factory reset requests to reset system \n");
                    request_reboot();
                    return;
                }
                break;
#ifdef MODULE_TEST
        case CMD_CODE_SYSMONITOR_TEST_MODULE:
            dbgprintf(DEBUG_ERROR, stderr, "----- test module fwmgr ----- %04x\n", CMD_CODE_SYSMONITOR_TEST_MODULE);
            while(1)
            {

            }
            break;
#endif				
            default:
                printf("%s, msg cmd %d not supported \n", __func__, cmd->cmdCode);
                ret = fw_not_supported;
                break;
            }


            if( fw_ret_ok == ret )
            {
                reportFwmgrCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex,
                    PARA_VALUE_RESULT_SUCCESS, PARA_VALUE_ERROR_NO_ERROR);
            }
            else
            {
                reportFwmgrCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex,
                    PARA_VALUE_RESULT_FAILED, ret);
            }
			
        }
        else if( CMD_GET == cmd->cmdType )
        {
            switch( cmd->cmdCode ) {

            default:
                printf("%s, msg cmd %d not supported \n", __func__, cmd->cmdCode);
                break;
            }
            
            if( fw_ret_ok != ret )
            {
                reportFwmgrCmdResult(srcId, cmd->cmdCode, cmd->cmdIndex, PARA_VALUE_RESULT_FAILED, ret);
            }
        }
        else if( CMD_EVENT == cmd->cmdType )
        {
            switch( cmd->cmdCode ) {

            default:
                printf("%s, msg cmd %d not supported \n", __func__, cmd->cmdCode);
                break;
            }
        }
        else
        {
            printf("%s, cmd type %d not supported \n", __func__, cmd->cmdType);
        }

    }
    else if( MSG_TYPE_INTERNAL == header->msgType )
    {

    }
    else
    {
        printf("%s, msg type %d not supported \n", __func__, header->msgType);
    }
}

void fwmgr_msgqueue_init(void)
{
    key_t key = ftok("/tmp", MSGQ_FTOK_ID);
    if( key == (key_t) - 1 ) 
    {
        printf("ftok(%d) failed, %s\n", MSGQ_FTOK_ID, strerror(errno));
        exit(EXIT_FAILURE);
    }
    rx_queue_id = msgget(key, IPC_CREAT);

    key = ftok("/tmp", MSGQ_FTOK_ID ^ 0xff);
    if( key == (key_t) - 1 ) 
    {
        printf("ftok(%d) failed, %s\n", MSGQ_FTOK_ID ^ 0xff, strerror(errno));
        if( tx_queue_id != 0 )
        {   
            msgctl(rx_queue_id, IPC_RMID, NULL);
            rx_queue_id = 0;   
        }
        exit(EXIT_FAILURE);
    }
    tx_queue_id = msgget(key, IPC_CREAT);
}

static void* fwmgr_main(void *arg __attribute__((unused)))
{
    pthread_setname_np(pthread_self(), "fwmgr");
    
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_hdr = (MSGHEADER *)msg_buf;
    static int32_t cout = 0;
    while( ! stop_fwmgr_thread )
    {
        if( msgrcv(rx_queue_id, (void*)&msg_buf, MAX_MSG_SIZE, MSGQ_TYPE_FWM, IPC_NOWAIT) < 0 )
        {
            int err = errno;
            if( err <= 0 && err != EINTR )
            {
                printf("%s, msgrcv error %s\n", __func__, strerror(err));
            }
        }
        else
        {
            printf("%s, received msg from 0x%X, len=%d \n", __func__, msg_hdr->srcID, msg_hdr->msgLength);
            // debug_dump_buffer(msg_hdr->msgLength, msg_buf);
            fwmgr_tlvmsg_hdlr(msg_hdr);
        }
        sleep(1);
        if ( cout >= 5)
        {
            cout = 0;
            reportFwmgrHeartBeat();
        }
        cout++;

    }

    pthread_exit((void*)0);
}
#if 0
RESULT fwmgr_init()
{
    pthread_t thread;

    if( RC_OK != MOD_register(&mod_fwmgr_info) )
    {
        printf("Can't register module with syscore\n");
        return RC_FAIL;
    }

    pthread_create(&thread, NULL, fwmgr_main, 0);

    return RC_OK;
}
#endif

int main()
{
    void *arg = NULL;

    fwmgr_msgqueue_init();

    fwmgr_main(arg);

    return 0;
}
